package com.doodle.common.utils;

import android.database.AbstractCursor;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.DataSetObserver;

public class ComboCursor extends AbstractCursor {

	private Cursor[] mCursors;
	private Cursor mMainCursor;
	private Cursor mCursor; // updated in onMove
	
	private int[] mColumnTable;
	
	private DataSetObserver mObserver = new DataSetObserver() {

		@Override
		public void onChanged() {
			// Reset our position so the optimizations in move-related code
			// don't screw us over
			mPos = -1;
		}

		@Override
		public void onInvalidated() {
			mPos = -1;
		}
	};

	public ComboCursor(Cursor[] cursors, int mainIndex) {
		mCursors = cursors;
		mMainCursor = cursors[mainIndex];
		mCursor = cursors[0];

		for (int i = 0; i < mCursors.length; i++) {
			if (mCursors[i] == null)
				continue;

			mCursors[i].registerDataSetObserver(mObserver);
		}

		mColumnTable = new int[mMainCursor.getColumnCount()];
		buildColumnTable();
	}

	@Override
	public int getCount() {
		int count = 0;
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] != null) {
				count += mCursors[i].getCount();
			}
		}
		return count;
	}
	
	private void buildColumnTable() {
		String[] columnNames = getColumnNames();
		int i = 0;
		for (String columnName : columnNames) {
			mColumnTable[i++] = mCursor.getColumnIndex(columnName);
		}
	}
	
	@Override
	public boolean onMove(int oldPosition, int newPosition) {
		Cursor cursor = mCursor;
		boolean ret = onMoveInternal(oldPosition, newPosition);
		if (cursor != mCursor && mCursor != null) {
			buildColumnTable();
		}
		return ret;
	}
	
	public boolean onMoveInternal(int oldPosition, int newPosition) {
		/* Find the right cursor */
		mCursor = null;
		int cursorStartPos = 0;
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] == null) {
				continue;
			}

			if (newPosition < (cursorStartPos + mCursors[i].getCount())) {
				mCursor = mCursors[i];
				break;
			}

			cursorStartPos += mCursors[i].getCount();
		}

		/* Move it to the right position */
		if (mCursor != null) {
			boolean ret = mCursor.moveToPosition(newPosition - cursorStartPos);
			return ret;
		}
		return false;
	}
	
	private int covertColumn(int column) {
		if (mCursor == mMainCursor) {
			return column;
		} else {
			return mColumnTable[column];
		}
	}

	@Override
	public String getString(int column) {
		return mCursor.getString(covertColumn(column));
	}

	@Override
	public short getShort(int column) {
		return mCursor.getShort(covertColumn(column));
	}

	@Override
	public int getInt(int column) {
		return mCursor.getInt(covertColumn(column));
	}

	@Override
	public long getLong(int column) {
		return mCursor.getLong(covertColumn(column));
	}

	@Override
	public float getFloat(int column) {
		return mCursor.getFloat(covertColumn(column));
	}

	@Override
	public double getDouble(int column) {
		return mCursor.getDouble(covertColumn(column));
	}

	@Override
	public int getType(int column) {
		return mCursor.getType(covertColumn(column));
	}

	@Override
	public boolean isNull(int column) {
		return mCursor.isNull(covertColumn(column));
	}

	@Override
	public byte[] getBlob(int column) {
		return mCursor.getBlob(covertColumn(column));
	}

	@Override
	public String[] getColumnNames() {
		return mMainCursor.getColumnNames();
	}

	@Override
	public void deactivate() {
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] != null) {
				mCursors[i].deactivate();
			}
		}
		super.deactivate();
	}

	@Override
	public void close() {
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] == null)
				continue;
			mCursors[i].close();
		}
		super.close();
	}

	@Override
	public void registerContentObserver(ContentObserver observer) {
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] != null) {
				mCursors[i].registerContentObserver(observer);
			}
		}
	}

	@Override
	public void unregisterContentObserver(ContentObserver observer) {
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] != null) {
				mCursors[i].unregisterContentObserver(observer);
			}
		}
	}

	@Override
	public void registerDataSetObserver(DataSetObserver observer) {
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] != null) {
				mCursors[i].registerDataSetObserver(observer);
			}
		}
	}

	@Override
	public void unregisterDataSetObserver(DataSetObserver observer) {
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] != null) {
				mCursors[i].unregisterDataSetObserver(observer);
			}
		}
	}

	@Override
	public boolean requery() {
		int length = mCursors.length;
		for (int i = 0; i < length; i++) {
			if (mCursors[i] == null) {
				continue;
			}

			if (mCursors[i].requery() == false) {
				return false;
			}
		}

		return true;
	}
	
	public Cursor getCurrentCursor() {
		return mCursor;
	}
}